﻿/* **************************************************************************
 *
 * Copyright 2007-2010 Jeff Hardy
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * *************************************************************************/

using System.Collections.Generic;
using System.IO;
using Microsoft.Scripting.Hosting;

namespace NWSGI
{
    class WsgiApplicationCache
    {
        private Dictionary<string, WsgiApplication> scriptApplications = new Dictionary<string, WsgiApplication>();
        private IWsgiConfig config;
        private ScriptEngine engine;

        public WsgiApplicationCache(ScriptEngine engine, IWsgiConfig config)
        {
            this.engine = engine;
            this.config = config;
        }

        /// <summary>
        /// Get the object for this application. This will use the cached values if they exist.
        /// </summary>
        /// <returns>The object representing the application, or null if no suitable app can be found.</returns>
        public WsgiApplication GetApplication(IWsgiContext context)
        {
            return UseWildcardApplication(context) ?? UseMappedApplication(context) ?? UseFileApplication(context);
        }

        /// <summary>
        /// Handle wildcard requests (no .wsgi file in the URL)
        /// </summary>
        private WsgiApplication UseWildcardApplication(IWsgiContext context)
        {
            WsgiApplication application;
            if(!scriptApplications.TryGetValue("*", out application) && config.HasWildcard)
            {
                application = new WsgiApplication(engine, config, context, config.Wildcard.PhysicalPath, config.Wildcard.Callable);
            }

            return application;
        }

        /// <summary>
        /// Not a wildcard, so check for script mappings
        /// </summary>
        private WsgiApplication UseMappedApplication(IWsgiContext context)
        {
            foreach(ScriptMappingElement mapping in config.ScriptMappings)
            {
                if(context.Request.ScriptName.EndsWith(mapping.ScriptName))
                {
                    WsgiApplication application;
                    if(!scriptApplications.TryGetValue(mapping.ScriptName, out application))
                    {
                        // If physicalPath is empty and callable is not a dotted path,
                        // assume physicalPath = "~/$scriptName".
                        string path = string.IsNullOrEmpty(mapping.PhysicalPath)
                                && !string.IsNullOrEmpty(mapping.Callable)
                                && mapping.Callable.IndexOf('.') < 0
                            ? "~/" + mapping.ScriptName
                            : mapping.PhysicalPath;

                        application = new WsgiApplication(engine, config, context, path, mapping.Callable);
                        scriptApplications.Add(mapping.ScriptName, application);
                    }

                    return application;
                }
            }

            return null;
        }

        /// <summary>
        /// The handler must be in the app directory, so just use that
        /// </summary>
        private WsgiApplication UseFileApplication(IWsgiContext context)
        {
            string filename = Path.GetFileName(context.Request.ScriptName);

            WsgiApplication application;
            if(!scriptApplications.TryGetValue(filename, out application))
            {
                application = new WsgiApplication(engine, config, context, context.Request.ScriptName, "application");
                scriptApplications.Add(filename, application);
            }

            return application;
        }
    }
}
